#include <stdio.h>
#include "ServiceMgr.h"
#include "base/core/os/debug.h"
#include "base/core/mem_tracker.h"
#include "base/core/com_define.h"
#include "base/core/random.h"
#include "base/core/log.h"
#include "base/core/Profiler.h"
#include <signal.h>

#ifdef WIN32
#include "Debug/Win32MiniDump.h"
#endif

bool g_isOpenProfile = false;

//namespace 
//{
//	static const int  s_maxLintCount    = 6000;
//	static const char s_logDirector[]   = "log";
//	static const char s_logFileIdenty[] = "mmo";
//}

#ifdef WIN32
static bool g_hasSetFont = false;
static CONSOLE_FONT_INFOEX g_OldConsoleFont;
#endif

void OnQuitSignal(int)
{
    LogAlwaysPrint("[server] Get quit signal!");
    g_GetServiceMgr().SetExitSignal();
}

#ifdef _WIN32
BOOL WINAPI ConsoleHandlerRoutine(DWORD dwCtrlType)
{
    // the system creates a new thread in the process to execute the handler function,
    // the win7 force terminal process in 5 second event if the function not return.
    MMO_USE_ARGUMENT(dwCtrlType);
    //dwCtrlType:
    //  CTRL_C_EVENT        CTRL+C signal was received
    //  CTRL_BREAK_EVENT    CTRL+BREAK signal was received
    //  CTRL_CLOSE_EVENT    the user closes the console (either by clicking Close on the console window's window menu, or by clicking the End Task button command from Task Manager). 
    OnQuitSignal(0);

    ULONGLONG time = GetTickCount64();
    for (int i = 0; i < 1000000; ++i) 
	{
		// wait main thread exit
        Sleep(500); 
        LogDebugFmtPrint("[server] quit used time:%llums", GetTickCount64() - time);
    }
    //Return TRUE. In this case, no other handler functions are called and 
    // the system terminates the process.
    return true; 
}

static bool _SetWin32ConsoleProperty()
{
    bool result  = false;
    int nRetCode = false;
    HANDLE hStdin   = INVALID_HANDLE_VALUE;
    HANDLE hStdount = INVALID_HANDLE_VALUE;
    //DWORD dwMode  = 0;
    COORD       BufferSize  = {256, 600};
    SMALL_RECT  WinRect     = {0, 0, 120, 50};
   
    hStdin = ::GetStdHandle(STD_INPUT_HANDLE);
    MMOLOG_PROCESS_ERROR(hStdin != INVALID_HANDLE_VALUE);

    hStdount = ::GetStdHandle(STD_OUTPUT_HANDLE);
    MMOLOG_PROCESS_ERROR(hStdount != INVALID_HANDLE_VALUE);

    SetDebugOutputCodePage(CP_UTF8);
    {
        SetConsoleOutputCP(936);
        GetCurrentConsoleFontEx(hStdount, FALSE, &g_OldConsoleFont);
        CONSOLE_FONT_INFOEX font;
        font.cbSize = sizeof(font);
        font.nFont = 0;
        font.dwFontSize.X = 8;
        font.dwFontSize.Y = 16;
        font.FontFamily = FF_DONTCARE;
        font.FontWeight = FW_NORMAL;
        wcscpy_s(font.FaceName, L"点阵字体");
        SetCurrentConsoleFontEx(hStdount, FALSE, &font); // change a font to support show UTF-8
        g_hasSetFont = true;
    }
    
    // set window size
    nRetCode = ::SetConsoleScreenBufferSize(hStdount, BufferSize);
    nRetCode = ::SetConsoleWindowInfo(hStdount, true, &WinRect);
    nRetCode = ::SetConsoleTextAttribute(hStdount, FOREGROUND_GREEN);
    MMOLOG_PROCESS_ERROR(nRetCode);

    nRetCode = ::SetConsoleCtrlHandler(&ConsoleHandlerRoutine, TRUE);
    MMOLOG_PROCESS_ERROR(nRetCode);

    result = true;
Exit0: 
    return result;
}

static void _RestoreWin32ConsoleProperty() 
{
    if (g_hasSetFont) 
	{
        SetCurrentConsoleFontEx(::GetStdHandle(STD_OUTPUT_HANDLE), FALSE, &g_OldConsoleFont);
        g_hasSetFont = false;
    }
}

static bool _SetConsoleProperty()
{
    bool result  = false;
    bool retCode = false;

    _set_error_mode(_OUT_TO_MSGBOX);
    retCode = _SetWin32ConsoleProperty();
    MMOLOG_PROCESS_ERROR(retCode);
    result = true;
Exit0:
    return result;
}

#endif

#ifndef _WIN32
static bool _SetConsoleProperty()
{
    signal(SIGPIPE, SIG_IGN);
    signal(SIGSYS,  SIG_IGN);
    signal(SIGTERM, ::OnQuitSignal);  // when terminal by kill, call OnQuitSignal
    signal(SIGINT,  ::OnQuitSignal);   // when Ctrl+C, call OnQuitSignal
    return true;
}
#endif

int main(int argc, char* argv[])
{
	int result = false;
	bool retCode = false;
	const char* configFile = "./config.lua";
#ifdef WIN32
	Win32MiniDump g_Win32MiniDump;
#endif

    SetProfileThreadID();
    RandSeed((uint32_t)Time::Now().UnixSec(),
             (uint32_t)Time::Now().UnixMSec(),
             (uint32_t)Time::Now().UnixNano(),
             (uint32_t)Time::Tick());

    auto& serviceMgr = g_GetServiceMgr();

    MMO_USE_ARGUMENT(argc);
    MMO_USE_ARGUMENT(argv);
    std::locale loc = std::locale::global(std::locale(""));

	if (!_SetConsoleProperty())
	{
        printf("init service mgr fail, _SetConsoleProperty.");
		goto Exit0;
	}

	if (argc >= 2)
		configFile = argv[1];

    retCode = serviceMgr.Init(configFile);
    if (!retCode) 
	{
        printf("init service mgr fail, input enter to quit.");
        serviceMgr.UnInit();
        getchar();
        goto Exit0;
    }

    while (serviceMgr.Loop());

    LogAlwaysPrint("mmo server begin close...");

    retCode = serviceMgr.UnInit();
    MMOLOG_PROCESS_ERROR(retCode);

#ifdef CHECK_MEM_LEAK
    g_MemTracker().PrintMemLink("./memorylink.log");
#endif  // CHECK_MEM_LEAK

    LogAlwaysPrint("mmo server closed");

    result = true;
Exit0:
    ShutdownLog();
	std::locale::global(std::locale("C"));
#ifdef WIN32
    _RestoreWin32ConsoleProperty();
#endif
    return result ? 0 : -1;
}
